﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text;
using System.Net.Sockets;
using Kugar.Core.ExtMethod;
using Kugar.Core.ExtMethod.Serialization;

namespace Kugar.Core.Communications.FileTransfer
{
    internal static class GencelBuffer
    {
        static GencelBuffer()
        {
            Buffer = BufferManager.CreateBufferManager(4096 * 4096 * 10, 40960);
        }

        public static BufferManager Buffer { private set; get; }
    }

    [Serializable]
    public class FileTransfer_TransferRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferRequest);

        public string TaskName;
        public TransferType TransferType;
        public int MainSessionID;
        public int FileCount;
        public int TotalFileLength;
        public string TargetFolderName;
        public FileTransfer_FileInfo[] FileInfos;

        public static FileTransfer_TransferRequest Load(byte[] buffer,int startIndex,int length)
        {
             if (length<=12 ||  !buffer.IsInEnableRange(startIndex,length))
            {
                return null;
            }

             if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferRequest)
            {
                return null;
            }

            var temp = buffer.DeserializeToObject<FileTransfer_TransferRequest>(startIndex+4, length-4);

            //var temp = new TransferRequest();

            //temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex+4);
            //temp.TransferType = (TransferType)BitConverter.ToInt32(buffer, startIndex+8);

            //var ind=Array.FindIndex(buffer, 12, s => s == (byte) '|');

            //temp.TaskName = Encoding.Unicode.GetString(buffer, startIndex + 12, ind-12-startIndex);

            //temp.FileInfos = buffer.DeserializeToObject<TransferFileInfo[]>(startIndex + 13 + (ind - 12 - startIndex),
            //                                                                length - startIndex + 13 +
            //                                                                (ind - 12 - startIndex));

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var data = this.SerializeToByte();

            //var taskNameBytes = Encoding.Unicode.GetBytes(TaskName);

            ////var buf = new byte[12 + taskNameBytes.Length];

            //var filebuf = this.FileInfos.SerializeToByte();

            var buf = GencelBuffer.Buffer.TakeBuffer(4+data.Length);

            Array.Copy(cmdArr,buf,4);
            Array.Copy(data,0,buf,4,data.Length);

      //      var t = this.SerializeToByte();

      //Converter.GetBytes(MainSessionID),0,buf,4,4);
      //      Array.Copy(BitConverter.GetBytes((int)TransferType),0,buf,8,4);
      //      Array.Copy(taskNameBytes,0,buf,12,taskNameBytes.Length);

      //      buf[12 + taskNameBytes.Length] = (byte) '|';

      //      Array.Copy(filebuf, 0, buf, 13 + taskNameBytes.Length, filebuf.Length);

            return new ArraySegment<byte>(buf, 0, 4 + data.Length);
        }
    }

    [Serializable]
    public class FileTransfer_FileInfo
    {
        public string FileName;
        public int FileSize;
        public int FileID;
    }

    /// <summary>
    ///     应答TransferRequest消息
    /// </summary>
    [Serializable]
    public class FileTransfer_TransferResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferResponse);

        public bool IsEnableTransfer = true;

        public int MainSessionID;

        public static FileTransfer_TransferResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 9 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferResponse)
            {
                return null;
            }

            var temp = new FileTransfer_TransferResponse();


            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex+4);
            temp.IsEnableTransfer = BitConverter.ToBoolean(buffer, startIndex+8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            //var buf = new byte[10];

            var buf = GencelBuffer.Buffer.TakeBuffer(9);

            Array.Copy(cmdArr, buf,4);

            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);

            Array.Copy(BitConverter.GetBytes(IsEnableTransfer), 0, buf, 8,1);


            return new ArraySegment<byte>(buf,0,9);
        }
    }

    /// <summary>
    ///     当发送方接收到FileTransfer_TransferResponse消息时,返回该消息,作为确认文件准备完毕,可以接受数据请求
    /// </summary>
    [Serializable]
    public class FileTransfer_TransferBegin
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferBegin);

        public TransferType TransferType;
        public int MainSessionID;

        public static FileTransfer_TransferBegin Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 12 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferBegin)
            {
                return null;
            }

            var temp = new FileTransfer_TransferBegin();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            temp.TransferType = (TransferType)BitConverter.ToInt32(buffer, startIndex + 8);
            //temp.TaskName = Encoding.Unicode.GetString(buffer, startIndex + 12, length - 12);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            //var taskNameBytes = Encoding.Unicode.GetBytes(TaskName);

            //var buf = new byte[12 + taskNameBytes.Length];

            var buf = GencelBuffer.Buffer.TakeBuffer(12);//+ taskNameBytes.Length);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            Array.Copy(BitConverter.GetBytes((int)TransferType), 0, buf, 8, 4);
            //Array.Copy(taskNameBytes, 0, buf, 12, taskNameBytes.Length);

            return new ArraySegment<byte>(buf, 0, 12);
        }
    }

    /// <summary>
    ///     当接收方接收到FileTransfer_TransferBegin消息后,发送该消息,读取指定ID的文件的指定偏移量的指定数据
    /// </summary>
    [Serializable]
    public class FileTransfer_DataBlockRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int) CmdID.FileTransfer_DataBlockRequest);
        public int MainSessionID;
        public int FileID;
        public int GetOffset;
        public int GetCount;

        public static FileTransfer_DataBlockRequest Load(byte[] buffer,int startIndex,int length)
        {
            if (length<20 ||  !buffer.IsInEnableRange(startIndex,length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_DataBlockRequest)
            {
                return null;
            }

            var temp = new FileTransfer_DataBlockRequest();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex+4);
            temp.FileID = BitConverter.ToInt32(buffer, startIndex+8);
            temp.GetOffset = BitConverter.ToInt32(buffer, startIndex+12);
            temp.GetCount = BitConverter.ToInt32(buffer, startIndex+16);

            return temp;
        }

        public ArraySegment<byte > ToBytes()
        {

            var buf = GencelBuffer.Buffer.TakeBuffer(20);

            Array.Copy(cmdArr,buf,4);
            Array.Copy(BitConverter.GetBytes(MainSessionID),0,buf,4,4);
            Array.Copy(BitConverter.GetBytes(FileID),0,buf,8,4);
            Array.Copy(BitConverter.GetBytes(GetOffset), 0, buf, 12, 4);
            Array.Copy(BitConverter.GetBytes(GetCount), 0, buf, 16, 4);

            return new ArraySegment<byte>(buf,0,20);
        }
    }

    /// <summary>
    ///     发送方接收到FileTransfer_DataBlockRequest消息后,发送该消息,消息内容包含为请求的文件ID,文件偏移量,指定数量的数据
    /// </summary>
    [Serializable]
    public class FileTransfer_DataBlockResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_DataBlockResponse);
        public int MainSessionID;
        public int FileID;
        public int Offset;
        public ArraySegment<byte> Data;

        public static FileTransfer_DataBlockResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length<20 ||  !buffer.IsInEnableRange(startIndex,length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_DataBlockResponse)
            {
                return null;
            }

            var temp = new FileTransfer_DataBlockResponse();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex+4);
            temp.FileID = BitConverter.ToInt32(buffer, startIndex+8);
            temp.Offset = BitConverter.ToInt32(buffer, startIndex + 12);
            var count = BitConverter.ToInt32(buffer, startIndex+16);

            temp.Data = new ArraySegment<byte>(buffer, startIndex+20, count);

            return temp;
        }

        public ArraySegment<byte > ToBytes()
        {
            var buf=GencelBuffer.Buffer.TakeBuffer(20 + Data.Count);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);
            Array.Copy(BitConverter.GetBytes(Offset), 0, buf, 12, 4);
            Array.Copy(BitConverter.GetBytes(Data.Count), 0, buf, 16, 4);
            Array.Copy(Data.Array,Data.Offset,buf,20,Data.Count);

            return new ArraySegment<byte>(buf, 0, 20 + Data.Count);
        }
    }

    /// <summary>
    ///     当接收方读取完所有文件之后,发送该消息,作为通知发送方,所有文件以接收完毕
    /// </summary>
    public class FileTransfer_AllFileCompletedRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_AllFileCompletedRequest);

        public int MainSessionID;

        public static FileTransfer_AllFileCompletedRequest Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_AllFileCompletedRequest)
            {
                return null;
            }

            var temp = new FileTransfer_AllFileCompletedRequest();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(8);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    /// <summary>
    ///     当接收方读取完所有文件之后,发送该消息,作为通知发送方,所有文件以接收完毕
    /// </summary>
    public class FileTransfer_AllFileCompletedResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_AllFileCompletedRequest);

        public int MainSessionID;

        public static FileTransfer_AllFileCompletedResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_AllFileCompletedResponse)
            {
                return null;
            }

            var temp = new FileTransfer_AllFileCompletedResponse();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(8);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    
    /// <summary>
    ///     单文件传输结束
    /// </summary>
    public class FileTransfer_SingleFileCompletedRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_SingleFileCompletedRequest);

        public int MainSessionID;
        public int FileID;

        public static FileTransfer_SingleFileCompletedRequest Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 12 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_SingleFileCompletedRequest)
            {
                return null;
            }

            var temp = new FileTransfer_SingleFileCompletedRequest();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 12);
        }
    }

    /// <summary>
    ///     单文件传输结束
    /// </summary>
    public class FileTransfer_SingleFileCompletedResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_SingleFileCompletedResponse);

        public int MainSessionID;
        public int FileID;

        public static FileTransfer_SingleFileCompletedResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 12 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_SingleFileCompletedResponse)
            {
                return null;
            }

            var temp = new FileTransfer_SingleFileCompletedResponse();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 12);
        }
    }


    /// <summary>
    ///     发送方或接收方取消文件传输
    /// </summary>
    public class FileTransfer_TransferCancelRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferCancelRequest);

        public int MainSessionID;

        public static FileTransfer_TransferCancelRequest Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferCancelRequest)
            {
                return null;
            }

            var temp = new FileTransfer_TransferCancelRequest();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            //temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            //Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    /// <summary>
    ///     发送方或接收方处理完取消文件传输的请求之后，应答的消息
    /// </summary>
    public class FileTransfer_TransferCancelResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferCancelResponse);

        public int MainSessionID;

        public static FileTransfer_TransferCancelResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferCancelResponse)
            {
                return null;
            }

            var temp = new FileTransfer_TransferCancelResponse();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            //temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            //Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    /// <summary>
    ///     发送方或接收方取消文件传输
    /// </summary>
    public class FileTransfer_TransferActivityRequest
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferActivityRequest);

        public int MainSessionID;

        public static FileTransfer_TransferActivityRequest Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferActivityRequest)
            {
                return null;
            }

            var temp = new FileTransfer_TransferActivityRequest();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            //temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            //Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    /// <summary>
    ///     发送方或接收方处理完取消文件传输的请求之后，应答的消息
    /// </summary>
    public class FileTransfer_TransferActivityResponse
    {
        private static readonly byte[] cmdArr = BitConverter.GetBytes((int)CmdID.FileTransfer_TransferActivityResponse);

        public int MainSessionID;

        public static FileTransfer_TransferActivityResponse Load(byte[] buffer, int startIndex, int length)
        {
            if (length < 8 || !buffer.IsInEnableRange(startIndex, length))
            {
                return null;
            }

            if (buffer[startIndex] != (byte)CmdID.FileTransfer_TransferActivityResponse)
            {
                return null;
            }

            var temp = new FileTransfer_TransferActivityResponse();

            temp.MainSessionID = BitConverter.ToInt32(buffer, startIndex + 4);
            //temp.FileID = BitConverter.ToInt32(buffer, startIndex + 8);

            return temp;
        }

        public ArraySegment<byte> ToBytes()
        {
            var buf = GencelBuffer.Buffer.TakeBuffer(12);

            Array.Copy(cmdArr, buf, 4);
            Array.Copy(BitConverter.GetBytes(MainSessionID), 0, buf, 4, 4);
            //Array.Copy(BitConverter.GetBytes(FileID), 0, buf, 8, 4);

            return new ArraySegment<byte>(buf, 0, 8);
        }
    }

    public enum CmdID
    {
        //发送方发送该消息作为请求文件传输
        FileTransfer_TransferRequest=1,

        //接收方回应是否允许发送
        FileTransfer_TransferResponse,

        //发送方接到接收方的TransferResponse消息后,发送该消息作为确认已准备好文件传输
        FileTransfer_TransferBegin,

        //由接收方发送到发送方的信息,用于请求指定偏移量以及指定读取数量
        FileTransfer_DataBlockRequest,

        //由发送方应答文件接收方,传递实际的文件数据
        FileTransfer_DataBlockResponse,

        //其中一方取消传输过程
        FileTransfer_TransferCancelRequest,

        FileTransfer_TransferCancelResponse,

        //单文件传输结束
        FileTransfer_SingleFileCompletedRequest,

        //单文件传输结束
        FileTransfer_SingleFileCompletedResponse,

        //传输结束
        FileTransfer_AllFileCompletedRequest,

        FileTransfer_AllFileCompletedResponse,

        //其中一方取消传输过程
        FileTransfer_TransferActivityRequest,

        FileTransfer_TransferActivityResponse,

        //应答传输结束
        TransferRequestEndResponse,
    }

    public enum TransferType
    {
        File,
        Directory
    }
    
}
